package com.wang.lottery.domain.activity.service.partake.impl;

import cn.bugstack.middleware.db.router.strategy.IDBRouterStrategy;
import com.wang.lottery.common.Constants;
import com.wang.lottery.common.Result;
import com.wang.lottery.domain.activity.model.po.UserTakeActivity;
import com.wang.lottery.domain.activity.model.req.PartakeReq;
import com.wang.lottery.domain.activity.model.res.StockResult;
import com.wang.lottery.domain.activity.model.vo.ActivityBillVO;
import com.wang.lottery.domain.activity.model.vo.InvoiceVO;
import com.wang.lottery.domain.activity.repository.IUserStrategyExportRepository;
import com.wang.lottery.domain.activity.repository.IUserTakeActivityCountRepository;
import com.wang.lottery.domain.activity.repository.IUserTakeActivityRepository;
import com.wang.lottery.domain.activity.service.partake.BaseActivityPartake;
import com.wang.lottery.domain.award.model.vo.DrawOrderVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.util.List;

/**
 * @author wjh
 * @create 2023-11-08 13:25
 * 活动参与功能实现
 */
@Slf4j
@Service
public class ActivityPartakeImpl extends BaseActivityPartake {
    
    @Resource
    private IDBRouterStrategy dbRouter;
    @Resource
    private TransactionTemplate transactionTemplate;
    @Resource
    private IUserTakeActivityRepository userTakeActivityRepository;
    @Resource
    private IUserTakeActivityCountRepository userTakeActivityCountRepository;
    @Resource
    private IUserStrategyExportRepository userStrategyExportRepository;


    /**
     * 释放活动库存锁
     * @param stockKey 库存锁
     */
    @Override
    protected void recoverActivityCacheStockByRedis(String stockKey) {
        activityRepository.recoverActivityCacheStockByRedis(stockKey);
    }

    /**
     * 活动信息校验处理，把活动库存、状态、日期、个人参与次数
     *
     * @param partake 参与活动请求
     * @param bill    活动账单
     * @return 校验结果
     */
    @Override
    protected Result checkActivityBill(PartakeReq partake, ActivityBillVO bill) {
        //校验，活动状态，活动状态必须是执行中
        if (!Constants.ActivityState.DOING.getCode().equals(bill.getState())) {
            log.warn("活动当前状态非可用 state：{}", bill.getState());
            return Result.buildResult(Constants.ResponseCode.UN_ERROR.getCode(), "当前活动非可用");
        }
        //校验活动日期
        if (bill.getBeginDateTime().after(partake.getPartakeDate()) || bill.getEndDateTime().before(partake.getPartakeDate())) {
            log.warn("活动时间范围非可用 beginDateTime：{} endDateTime：{}", bill.getBeginDateTime(), bill.getEndDateTime());
            return Result.buildResult(Constants.ResponseCode.UN_ERROR.getCode(), "当前时间不是活动范围时间");
        }
        //校验活动库存
        if (bill.getStockSurplusCount() <= 0) {
            log.warn("活动剩余库存非可用 stockSurplusCount：{}", bill.getStockSurplusCount());
            return Result.buildResult(Constants.ResponseCode.UN_ERROR.getCode(), "活动库存不足");
        }
        //校验个人剩余领取次数
        if (bill.getUserTakeLeftCount() <= 0) {
            log.warn("个人领取次数非可用 userTakeLeftCount：{}", bill.getUserTakeLeftCount());
            return Result.buildResult(Constants.ResponseCode.UN_ERROR.getCode(), "个人领取次数非可用");
        }
        return Result.buildSuccessResult();
    }

    /**
     * 这个是扣减activity表的库存
     *
     * @param req 参与活动请求
     * @param stockCount 剩余库存数量
     * @return 扣减结果
     */
    @Override
    protected StockResult subtractionActivityStockByRedis(PartakeReq req,Integer stockCount) {
        return super.activityRepository.subtractionActivityStockByRedis(req, stockCount);
        
    }

    /**
     * 这个方法是扣减个人已参与次数，修改user_take_activity_count表的数据，插入领取活动信息，新增user_take_activity表的数据
     *
     * @param partake 参与活动请求
     * @param bill    活动账单
     * @return 领取结果
     */
    @Override
    protected Result grabActivity(PartakeReq partake, ActivityBillVO bill, Long takeId) {
        //涉及两张表，
        try {
            dbRouter.doRouter(partake.getuId());
            return transactionTemplate.execute(status -> {
                try {
                    // 扣减个人已参与次数，修改user_take_activity_count表的数据
                    boolean flag = userTakeActivityCountRepository.subtractionLeftCount(partake.getActivityId(), partake.getuId(), bill.getTakeCount(), bill.getUserTakeLeftCount());
                    if (!flag) {
                        status.setRollbackOnly();
                        log.error("领取活动，扣减个人已参与次数失败 activityId：{} uId：{}", partake.getActivityId(), partake.getuId());
                        return Result.buildResult(Constants.ResponseCode.NO_UPDATE.getCode(),Constants.ResponseCode.NO_UPDATE.getInfo());
                    }
                    // 插入领取活动信息，新增user_take_activity表的数据，
                    userTakeActivityRepository.takeActivity(bill,takeId,partake.getPartakeDate(),bill.getTakeCount() - bill.getUserTakeLeftCount() + 1,bill.getStrategyId());
                } catch (DuplicateKeyException e) {
                    status.setRollbackOnly();
                    log.error("领取活动，唯一索引冲突 activityId：{} uId：{}", partake.getActivityId(), partake.getuId(), e);
                    return Result.buildResult(Constants.ResponseCode.INDEX_DUP.getCode(),Constants.ResponseCode.INDEX_DUP.getInfo());
                }
                return Result.buildSuccessResult();
            });
        } finally {
            dbRouter.clear();
        }
    }
    @Override
    protected UserTakeActivity queryNoConsumedTakeActivityOrder(Long activityId, String uId) {
        return userTakeActivityRepository.queryNoConsumedTakeActivityOrder(activityId,uId);
    }

    /**
     * 记录抽奖订单
     *
     * @param drawOrder 奖品订单
     * @return 保存结果
     */
    @Override
    public Result recordDrawOrder(DrawOrderVO drawOrder) {
        
        try {
            dbRouter.doRouter(drawOrder.getuId());
            return transactionTemplate.execute(status -> {
                try {
                    boolean flag = userTakeActivityRepository.lockTackActivity(drawOrder.getuId(),drawOrder.getActivityId());
                    if (!flag) {
                        status.setRollbackOnly();
                        log.error("记录中奖单，个人参与活动抽奖已消耗完  uId：{} activityId：{}", drawOrder.getuId(), drawOrder.getActivityId());
                        return Result.buildResult(Constants.ResponseCode.NO_UPDATE.getCode(),Constants.ResponseCode.NO_UPDATE.getInfo());
                    }
                    userStrategyExportRepository.saveUserStrategyExport(drawOrder);
                } catch (DuplicateKeyException e) {
                    status.setRollbackOnly();
                    //打印日志
                    log.error("记录中奖单，唯一索引冲突  uId：{} activityId：{}", drawOrder.getuId(), drawOrder.getActivityId(), e);
                    return Result.buildResult(Constants.ResponseCode.INDEX_DUP.getCode(),Constants.ResponseCode.INDEX_DUP.getInfo());
                }
                return Result.buildSuccessResult();
            });
        } finally {
            dbRouter.clear();
        }
    }

    /**
     * 更新发货单MQ状态
     *
     * @param uId     用户ID
     * @param orderId 订单ID
     * @param code    MQ 发送状态
     */
    @Override
    public void updateInvoiceMqState(String uId, Long orderId, Integer code) {
        userStrategyExportRepository.updateInvoiceMqState(uId, orderId, code);
    }

    /**
     * 扫描发货单 MQ 状态，把未发送 MQ 的单子扫描出来，做补偿
     *
     * @param dbNumber 分库号
     * @param tbNumber 分表号
     * @return 未发送 MQ 的单子
     */
    @Override
    public List<InvoiceVO> scanInvoiceMqState(int dbNumber, int tbNumber) {
        try {
            //设置路由
            dbRouter.setDBKey(dbNumber);
            dbRouter.setTBKey(tbNumber);
            //查询数据
            return userStrategyExportRepository.scanInvoiceMqState();
        } finally {
            //清理分库分表的路由
            dbRouter.clear();
        }
    }
}
